package xcmg.device.service.order;


import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.order.GpsMmJisoPoHeadDO;
import xcmg.device.dao.entity.order.SubcontractingOrderDO;
import xcmg.device.dao.entity.order.SubcontractingOutDO;
import xcmg.device.dao.entity.order.SubcontractingOutDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryDetailDO;
import xcmg.device.dao.mapper.order.SubcontractingOutDetailMapper;
import xcmg.device.dao.mapper.order.SubcontractingOutMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryMapper;
import xcmg.device.infra.BeanUtil;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.infra.exception.CommonBusiExceptions;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.basic.CommonGenService;
import xcmg.device.service.vo.order.GpsMmJisoPoHeadVO;
import xcmg.device.service.vo.order.GpsMmJisoPoLineVoteVO;
import xcmg.device.service.vo.order.SubcontractingOrderDetailVO;
import xcmg.device.service.vo.order.SubcontractingOrderVO;
import xcmg.device.service.vo.order.SubcontractingOutDetailVO;
import xcmg.device.service.vo.order.SubcontractingOutVO;
import xcmg.device.util.CommonUtils;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.util.PageHelperPlus;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * SubcontractingOut 后台接口实现类
 */
@Slf4j
@Service
public class SubcontractingOutService {

    @Autowired
    private SubcontractingOutMapper subcontractingOutMapper;

    @Autowired
    private SubcontractingOutDetailMapper subcontractingOutDetailMapper;
    @Autowired
    private WarehouseDeliveryMapper warehouseDeliveryMapper;

    @Autowired
    private WarehouseDeliveryDetailMapper warehouseDeliveryDetailMapper;
    @Autowired
    private SubcontractingOrderService subcontractingOrderService;
    @Autowired
    private GpsMmJisoPoHeadService gpsMmJisoPoHeadService;
    @Autowired
    private CommonGenService commonGenService;
    @Autowired
    private GenDocumentService genDocumentService;

    public PageCommonVO<SubcontractingOutVO> list(SearchCommonVO<SubcontractingOutVO> condition) {
        PageCommonVO<SubcontractingOutVO> result = new PageCommonVO<>();
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        PageHelperPlus.orderBy("t.ID desc");
        List<SubcontractingOutVO> resultList = subcontractingOutMapper.queryList(condition.getFilters());
        result.setPageInfo(new PageInfo(resultList));
        List<SubcontractingOutVO> voList = BeanUtil.do2bo4List(resultList, SubcontractingOutVO.class);
        result.setPageInfoList(voList);
        return result;
    }

    public SubcontractingOutVO getVoById(String id) {
        SubcontractingOutVO m = getById(id);
        if (m != null) {
            collectDetail(Collections.singletonList(m));
        }
        return m;
    }

    public SubcontractingOutVO getByCode(String code) {
        SubcontractingOutVO vo = new SubcontractingOutVO();
        vo.setCode(code);
        List<SubcontractingOutVO> resultList = subcontractingOutMapper.queryList(vo);
        if (null != resultList && !resultList.isEmpty()) {
            return resultList.get(0);
        }
        return null;
    }

    public SubcontractingOutVO getVoByCode(String code) {
        SubcontractingOutVO m = getByCode(code);
        if (m != null) {
            collectDetail(Collections.singletonList(m));
        }
        return m;
    }

    private void collectDetail(List<SubcontractingOutVO> subcontractingOutVOS) {
        List<String> ids = subcontractingOutVOS.stream().map(SubcontractingOutVO::getId).collect(Collectors.toList());
        SubcontractingOutDetailVO dv = new SubcontractingOutDetailVO();
        dv.setFids(ids);
        List<SubcontractingOutDetailVO> subcontractingOutDetails = subcontractingOutDetailMapper.queryList(dv);
        Map<String, List<SubcontractingOutDetailVO>> map = subcontractingOutDetails.stream().collect(Collectors.groupingBy(SubcontractingOutDetailVO::getFid));
        subcontractingOutVOS.forEach(m -> m.setDetails(map.get(m.getId())));
    }

    public SubcontractingOutVO getById(String id) {
        SubcontractingOutVO vo = new SubcontractingOutVO();
        vo.setId(id);
        List<SubcontractingOutVO> resultList = subcontractingOutMapper.queryList(vo);
        if (null != resultList && !resultList.isEmpty()) {
            return resultList.get(0);
        }
        return null;
    }


    @Transactional
    public boolean saveSubcontractingOut(SubcontractingOutVO v) {
        checkAddStep1(v);
        switch (v.getSource()) {
            case 0:
                return doSaveFromSubconncting(v);
            case 1:
                return doSaveFromJiso(v);
            default:
                log.error("来源参数错误");
                return false;
        }
    }

    private boolean doSaveFromSubconncting(SubcontractingOutVO v) {
        v.setId(commonGenService.textIdWithException());
        v.setCode(genDocumentService.genDocumentNoSeq(BillDesc.ZBCK));
        checkAddFromSubcontracting(v);
        doSaveSubcontractingOut(v);
        SubcontractingOrderDO sod = new SubcontractingOrderDO();
        sod.setId(v.getSubcontOrderId());
        sod.setUpdatedTime(new Date());
        sod.setUpdateId(v.getUpdateId());
        sod.setDeliveryState(1);
        subcontractingOrderService.updateById(sod);
        return true;
    }

    private boolean doSaveFromJiso(SubcontractingOutVO v) {
        Long orderId = CommonUtils.tryParseLongWithError(v.getSubcontOrderId(), "订单ID参数错误");
        List<String> detailIds = v.getDetails().stream().map(SubcontractingOutDetailVO::getSubcontOrderDetailId).collect(Collectors.toList());
        GpsMmJisoPoHeadVO item = gpsMmJisoPoHeadService.getVoById(orderId, v.getOrgId());
        if (item == null || CollectionUtils.isEmpty(item.getDetailList())) {
            throw new CommonBusiExceptions("找不到对应的订单");
        }
        if (item.getDeliveryState() != 0) {
            throw new CommonBusiExceptions("同步订单已经创建过发货单");
        }
        List<GpsMmJisoPoLineVoteVO> details = item.getDetailList();
        Map<String, GpsMmJisoPoLineVoteVO> map = new HashMap<>();
        details.forEach(d -> {
            if (detailIds.contains(String.valueOf(d.getPoLineId()))) {
                GpsMmJisoPoLineVoteVO dd = map.get(d.getItem());
                if (null == dd) {
                    map.put(d.getItem(), d);
                } else {
                    dd.setQty(dd.getQty() + d.getQty());
                    map.put(d.getItem(), dd);
                }
            }
        });
        v.setId(commonGenService.textIdWithException());
        v.setCode(genDocumentService.genDocumentNoSeq(BillDesc.ZBCK));
        Date now = new Date();
        v.setCreatedTime(now);
        v.setUpdatedTime(now);
        v.setSubcontOrderCode(null);
        v.setOrderNo(item.getPoNumber());
        v.setOrgId(v.getOrgId());
        v.setSupplierNo(item.getSupplierno());
        v.setSupplierName(item.getSupplierName());
        v.setSupplierOrgId(item.getOrgId());
        v.setFactory(item.getArrFactory());
        v.setOutboundStatus(0);
        v.setSource(1);
        List<SubcontractingOutDetailVO> outDetails = new ArrayList<>();
        for (GpsMmJisoPoLineVoteVO svd : map.values()) {
            SubcontractingOutDetailVO detailVO = new SubcontractingOutDetailVO();
            BeanUtils.copyProperties(svd, detailVO);
            detailVO.setId(commonGenService.textIdWithException());
            detailVO.setComponentNo(svd.getItem());
            detailVO.setMaterialsDes(svd.getMaterialsDes());
            detailVO.setMaterialsShortNo(svd.getMaterialsShortNo());
            detailVO.setPackageUnit(null);
            detailVO.setFid(v.getId());
            detailVO.setSubcontOrderDetailId(null);
            detailVO.setPlanAmount(BigDecimal.valueOf(svd.getQty()));
            detailVO.setRealAmount(BigDecimal.ZERO);
            detailVO.setFid(v.getId());
            detailVO.setOutboundStatus(0);
            detailVO.setCreatedTime(now);
            detailVO.setUpdatedTime(now);
            outDetails.add(detailVO);
        }
        v.setDetails(outDetails);
        doSaveSubcontractingOut(v);
        GpsMmJisoPoHeadDO gpsMmJisoPoHeadDO = new GpsMmJisoPoHeadDO();
        gpsMmJisoPoHeadDO.setPoHeadId(orderId);
        gpsMmJisoPoHeadDO.setUpdateTime(new Date());
        gpsMmJisoPoHeadDO.setUpdateId(v.getUpdateId());
        gpsMmJisoPoHeadDO.setDeliveryState(1);
        gpsMmJisoPoHeadService.updateById(gpsMmJisoPoHeadDO);
        return true;
    }

    private boolean doSaveSubcontractingOut(SubcontractingOutVO v) {
        SubcontractingOutDO m = BeanUtil.do2bo(v, SubcontractingOutDO.class);
        subcontractingOutMapper.save(m);
        v.getDetails().forEach(d -> {
            SubcontractingOutDetailDO dm = BeanUtil.do2bo(d, SubcontractingOutDetailDO.class);
            dm.setFid(m.getId());
            subcontractingOutDetailMapper.save(dm);
        });
        saveDelivery(v);
        return true;
    }

    private void checkAddStep1(SubcontractingOutVO m) {
        List<Integer> ds = Arrays.asList(0, 1);
        if (null == m.getSource()) {
            throw new CommonBusiExceptions("无订单来源");
        }
        if (!ds.contains(m.getSource())) {
            throw new CommonBusiExceptions("订单来源无效");
        }
        if (StringUtils.isBlank(m.getSubcontOrderId())) {
            throw new CommonBusiExceptions("转包单ID不能为空");
        }
        if (CollectionUtils.isEmpty(m.getDetails())) {
            throw new CommonBusiExceptions("详情数据不存在");
        }
        for (SubcontractingOutDetailVO detailVO : m.getDetails()) {
            if (StringUtils.isBlank(detailVO.getSubcontOrderDetailId())) {
                throw new CommonBusiExceptions("转包单明细ID不能为空");
            }
        }
    }

    private void saveDelivery(SubcontractingOutVO v) {
        WarehouseDeliveryDO warehouseDeliveryDO = new WarehouseDeliveryDO();
        //主键
        warehouseDeliveryDO.setId(commonGenService.textIdWithException());
        //出库单号
        warehouseDeliveryDO.setDeliveryOrder(genDocumentService.genDocumentNoSeq(BillDesc.OutputNo));
        //业务单号（非正常出库单号）
        warehouseDeliveryDO.setBusinessOrder(v.getCode());
        //业务单别（非正常出库单单别）
        warehouseDeliveryDO.setBusinessSingle(BillDesc.ZBCK.getDesc());
        //备注
        warehouseDeliveryDO.setNote(null);
        //创建人
        warehouseDeliveryDO.setCreaterId(v.getCreateId());
        warehouseDeliveryDO.setCreaterName(v.getUpdateName());
        //状态
        warehouseDeliveryDO.setStatus(0);
        //创建时间
        warehouseDeliveryDO.setCreateDate(new Date());
        warehouseDeliveryDO.setOrgId(v.getOrgId());
        warehouseDeliveryDO.setWarehouseCode(v.getOutWarehouse());
        warehouseDeliveryDO.setOutArea(v.getOutArea());
        warehouseDeliveryDO.setSapOutArea(null);
        warehouseDeliveryDO.setNote(v.getNote());
        warehouseDeliveryDO.setSplitOrder(null);
        for (SubcontractingOutDetailVO abnormalOutDetailVO : v.getDetails()) {
            WarehouseDeliveryDetailDO warehouseDeliveryDetailDO = new WarehouseDeliveryDetailDO();

            warehouseDeliveryDetailDO.setId(commonGenService.textIdWithException());
            warehouseDeliveryDetailDO.setDeliveryOrder(warehouseDeliveryDO.getDeliveryOrder());
            warehouseDeliveryDetailDO.setBusinessSingle(BillDesc.ZBCK.getDesc());
            warehouseDeliveryDetailDO.setBusinessOrder(v.getCode());
            warehouseDeliveryDetailDO.setMaterialNo(abnormalOutDetailVO.getComponentNo());
            warehouseDeliveryDetailDO.setMaterialType(null);
            warehouseDeliveryDetailDO.setRealAmount(BigDecimal.ZERO);
            warehouseDeliveryDetailDO.setAmount(abnormalOutDetailVO.getPlanAmount());
            warehouseDeliveryDetailDO.setUnit(abnormalOutDetailVO.getPackageUnit());
            warehouseDeliveryDetailDO.setCreaterId(v.getCreateId());
            warehouseDeliveryDetailDO.setCreaterName(v.getUpdateName());
            warehouseDeliveryDetailDO.setCreateDate(new Date());
            warehouseDeliveryDetailDO.setMaterialName(abnormalOutDetailVO.getMaterialsDes());
            warehouseDeliveryDetailDO.setStatus(0);
            warehouseDeliveryDetailDO.setOrgId(v.getOrgId());
            warehouseDeliveryDetailMapper.insert(warehouseDeliveryDetailDO);
        }
        warehouseDeliveryMapper.insert(warehouseDeliveryDO);
    }

    private void checkAddFromSubcontracting(SubcontractingOutVO m) {
        SubcontractingOrderVO sv = subcontractingOrderService.getById(m.getSubcontOrderId());
        if (null == sv || !StringUtils.equals(sv.getOrgId(), m.getOrgId())) {
            throw new CommonBusiExceptions("转包单不存在");
        }
        if (sv.getState() != 2) {
            throw new CommonBusiExceptions("转包单状态异常:未完成入库");
        }
        if (sv.getDeliveryState() != 0) {
            throw new CommonBusiExceptions("转包单已经创建过发货单");
        }
        Date now = new Date();
        m.setCreatedTime(now);
        m.setUpdatedTime(now);
        m.setSubcontOrderCode(sv.getCode());
        m.setOrderNo(sv.getOrderNo());
        m.setOrgId(sv.getOrgId());
        m.setSupplierNo(sv.getSupplierNo());
        m.setSupplierName(sv.getSupplierName());
        m.setSupplierOrgId(sv.getSupplierOrgId());
        m.setFactory(sv.getFactory());
        m.setOutboundStatus(0);
        Map<String, SubcontractingOrderDetailVO> svdMap = sv.getDetails().stream().collect(Collectors.toMap(SubcontractingOrderDetailVO::getId, x -> x));
        for (SubcontractingOutDetailVO detailVO : m.getDetails()) {
            String subcontOrderDetailId = detailVO.getSubcontOrderDetailId();
            if (!svdMap.containsKey(subcontOrderDetailId)) {
                throw new CommonBusiExceptions("转包单明细ID不存在");
            }
            SubcontractingOrderDetailVO svd = svdMap.get(subcontOrderDetailId);
            BeanUtils.copyProperties(svd, detailVO);
            detailVO.setId(commonGenService.textIdWithException());
            detailVO.setSubcontOrderDetailId(subcontOrderDetailId);
            detailVO.setPlanAmount(svd.getRealAmount());
            detailVO.setRealAmount(BigDecimal.ZERO);
            detailVO.setFid(m.getId());
            detailVO.setOutboundStatus(0);
            detailVO.setCreatedTime(now);
            detailVO.setUpdatedTime(now);
        }
    }

    @Transactional
    public boolean delByIds(String id, String userId) {
        log.info("删除出库单:{},{}", id, userId);
        SubcontractingOutVO v = getVoById(id);
        if (v == null) {
            return false;
        }
        if (null != v.getOutboundStatus() && v.getOutboundStatus() != 0) {
            throw new CommonBusiExceptions("数据已经出库,不允许删除");
        }
        switch (v.getSource()) {
            case 0: {
                SubcontractingOrderVO so = subcontractingOrderService.getById(v.getSubcontOrderId());
                SubcontractingOrderDO sod = new SubcontractingOrderDO();
                sod.setId(so.getId());
                sod.setUpdatedTime(new Date());
                sod.setUpdateId(userId);
                sod.setDeliveryState(0);
                subcontractingOrderService.updateById(sod);
                break;
            }
            case 1: {
                Long orderId = CommonUtils.tryParseLongWithError(v.getSubcontOrderId(), "订单ID参数错误");
                GpsMmJisoPoHeadDO gpsMmJisoPoHeadDO = new GpsMmJisoPoHeadDO();
                gpsMmJisoPoHeadDO.setPoHeadId(orderId);
                gpsMmJisoPoHeadDO.setUpdateTime(new Date());
                gpsMmJisoPoHeadDO.setUpdateId(v.getUpdateId());
                gpsMmJisoPoHeadDO.setDeliveryState(0);
                gpsMmJisoPoHeadService.updateById(gpsMmJisoPoHeadDO);
                break;
            }
            default:
                throw new CommonBusiExceptions("来源参数错误");
        }
        v.getDetails().forEach(d -> {
            subcontractingOutDetailMapper.deleteByPrimaryKeySelective(d.getId());
        });
        subcontractingOutMapper.deleteByPrimaryKeySelective(id);
        warehouseDeliveryMapper.deleteByBusinessOrder(v.getCode());
        warehouseDeliveryDetailMapper.deleteByBusinessOrder(v.getCode());
        return true;
    }

    @Transactional
    public boolean updateArea(SubcontractingOutVO v) {
        SubcontractingOutVO m = getById(v.getId());
        if (m == null) {
            throw new CommonBusiExceptions("数据不存在");
        }
        if (null != m.getOutboundStatus() && m.getOutboundStatus() != 0) {
            throw new CommonBusiExceptions("数据已出库,不允许更改");
        }
        SubcontractingOutDO dto = new SubcontractingOutDO();
        dto.setId(v.getId());
        dto.setOutWarehouse(v.getOutWarehouse());
        dto.setOutArea(v.getOutArea());
        dto.setUpdateId(v.getUpdateId());
        dto.setUpdatedTime(new Date());
        dto.setUpdateName(v.getUpdateName());
        subcontractingOutMapper.updateNotNullByPrimaryKeySelective(dto);
        WarehouseDeliveryDO wd = warehouseDeliveryMapper.findByBusinessOrder(m.getCode(), v.getOrgId());
        if (wd == null) {
            throw new CommonBusiExceptions("数据异常");
        }
        wd.setWarehouseCode(v.getOutWarehouse());
        wd.setOutArea(v.getOutArea());
        warehouseDeliveryMapper.updateByPrimaryKey(wd);
        return true;
    }

    public boolean updateByOutbound(String businessOrder, String materialNo, BigDecimal realAmount, Integer singleState,
                                    Integer totalState) {
        SubcontractingOutVO v = getVoByCode(businessOrder);
        if (v == null || CollectionUtils.isEmpty(v.getDetails())) {
            return false;
        }
        Date now = new Date();
        Map<String, SubcontractingOutDetailVO> map = v.getDetails().stream().collect(Collectors.toMap(SubcontractingOutDetailVO::getComponentNo, x -> x));
        SubcontractingOutDetailVO detailVO = map.get(materialNo);
        if (detailVO != null) {
            SubcontractingOutDetailDO detailDO = new SubcontractingOutDetailDO();
            detailDO.setId(detailVO.getId());
            detailDO.setRealAmount(realAmount);
            detailDO.setOutboundStatus(singleState);
            detailDO.setUpdatedTime(now);
            subcontractingOutDetailMapper.updateNotNullByPrimaryKeySelective(detailDO);
        }
        SubcontractingOutDO outDO = new SubcontractingOutDO();
        outDO.setId(v.getId());
        outDO.setOutboundStatus(totalState);
        outDO.setUpdatedTime(now);
        outDO.setOutTime(now);
        subcontractingOutMapper.updateNotNullByPrimaryKeySelective(outDO);
        return true;
    }
}
